<?php
/**
 * 数据表高级操作类
 * <p>包含对单表的增、删、改、查询、统计等操作的高级封装</p>
 * @package Base
 * @author leo
 * @version v1.0
 * @copyright xer345.com 2013-04-23
 * @link http://www.xer345.com
 */
if(function_exists('mysqli_query')){
	include_once dirname(__FILE__).'/DBi.class.php';
}else{
	include_once dirname(__FILE__).'/DB.class.php';
}

class DBase extends DB {
	
	/**
	 * 各个表的字段运行时缓存
	 * @var array
	 */
	private $_fields = array();
	/**
	 * 各个类LIKE查询配置
	 * @var array
	 */
	private $_likes = array();

	/**
	 * 对 MYSQL LIKE 的内容进行转义
	 * @param  string $str 查询内容
	 * @return string      转义后的查询内容
	 */
	public function mysql_like_quote($str){
		return strtr($str, array("\\\\" => "\\\\\\\\", '_' => '\_', '%' => '\%', "\'" => "\\\\\'"));
	}

	public function set_like($tbname, $likes = array()){
		if(empty($likes) || !is_array($likes))return false;
		if(!isset($likes['_join_']))$likes['_join_'] = 'AND';
		$likes['_join_'] = strtoupper(trim($likes['_join_']));
		if($likes['_join_'] != 'AND' && $likes['_join_'] != 'OR')$likes['_join_'] = 'AND';
		$likes['_join_'] = " {$likes['_join_']} ";
		return $this->_likes[$tbname] = $likes;
	}

	/**
	 * 根据查询配置组装查询子句
	 * @param  string $tbname 表名
	 * @param  array  $select 查询条件
	 * @return array         组装后的查询条件
	 */
	public function fmt_like($tbname, &$select = array()){
		if(empty($select) || !is_array($select) || empty($this->_likes[$tbname])){
			return false;
		}
		//if(!empty($this->_likes[$tbname]['_data_']))return $this->_likes[$tbname]['_data_'];
		/*array(
			'keyword'	=> 'title',
			'keyword'	=> array('title', 'username'),
			'keyword'	=> array('title', 'username', '_type_' => 'left'),
			'keyword'	=> array('title', 'username', '_type_' => 'right'),
			'_join_'	=> ' AND ',
			'_data_'	=> '',
		);*/
		$_like = $this->_likes[$tbname];
		$fields = $this->get_fields($tbname);
		$_lstr = array();
		foreach($select as $key => $value){
			if(empty($value))continue;
			if(array_key_exists($key, $_like)){
				if(is_string($_like[$key])){
					$field = $_like[$key];
					if(!array_key_exists($field, $fields))continue;
					$_lstr[] = "`{$field}` LIKE '%{$value}%'";
				}elseif(is_array($_like[$key])){
					if(array_key_exists('_type_', $_like[$key])){
						$type = $_like[$key]['_type_'];
						unset($_like[$key]['_type_']);
					}else{
						$type = 'all';
					}
					$_wh = array();
					foreach ($_like[$key] as $field) {
						if(!array_key_exists($field, $fields))continue;
						switch ($type) {
							case 'all':
								$_wh[] = "`{$field}` LIKE '%{$value}%'";
								break;
							case 'left':
								$_wh[] = "`{$field}` LIKE '%{$value}'";
								break;
							default:
								$_wh[] = "`{$field}` LIKE '{$value}%'";
								break;
						}
					}
					$_lstr[] = '('.(implode(' OR ', $_wh)).')';
				}
				unset($select[$key]);
			}
		}
		if(!empty($_lstr))$select['kept'] = " {$_like['_join_']} ".implode(" {$_like['_join_']} ", $_lstr);
		return $select;
	}

	/**
	 * 将数组转换为 SQL
	 *
	 * @param array $data 数组
	 * @param string $type 查询类型，添加、修改、列表
	 * @param STRING $link 连接符，与/或
	 * @return string SQL
	 */
	public function array2sql($tbname, $data, $type = '', $link = 'AND'){
		if(empty($data) || !is_array($data))return '';
		$fields = $this->get_fields($tbname);
		if($type == 'insert'){
			$str = array('key' => array(), 'val' => array());
			foreach($data as $key => $val){
				if(!array_key_exists($key, $fields))continue;
				$str ['key'][] = '`'.$key.'`';
				$str ['val'][] = $this->quote($val);
			}
			$dataStr = "(".implode(',', $str['key']).") VALUES (".implode(',', $str['val']).")";
		} elseif($type == 'update'){
			$dataStr = array();
			foreach($data as $key => $val){
				if(!array_key_exists($key, $fields))continue;
				$dataStr[] = "`$key`=".$this->quote($val);
			}
			$dataStr = implode(',', $dataStr);
		} elseif($type == 'order'){
			$dataStr = array();
			foreach($data as $key => $val){
				if(!array_key_exists($key, $fields))continue;
				$dataStr[] = "`$key` $val";
			}
			$dataStr = ' ORDER BY '.implode(',', $dataStr);
		} else {
			$dataStr = '1';
			foreach($data as $key => $val){
				if($key == 'kept'){ // 原封不动，尽量少用这个，哈哈
					$dataStr .= $val;
				} else {
					if(!array_key_exists($key, $fields) || $val === '')continue;
					if(!empty($dataStr)){
						$dataStr .= " $link ";
					}
					$dataStr .= "`$key`=".$this->quote($val);
				}
			}
			if($dataStr == '1'){
				$dataStr = '';
			}
		}
		return $dataStr;
	}
	
	/**
	 * 读取指定表的字段信息
	 * @param  stirng $tbname 表名
	 * @return array         字段信息
	 */
	public function get_fields($tbname){
		if(isset($this->_fields[$tbname]))return $this->_fields[$tbname];
		$res = $this->query("DESC `{$tbname}`");
        if ($res !== false){
            $this->_fields[$tbname] = array();
            while ($row = $this->fetch_row($res)){
                $this->_fields[$tbname][$row[0]] = array(
                	'name'		=> $row[0],
                	'type'		=> $row[1],
                	'null'		=> $row[2],
                	'key'		=> $row[3],
                	'default '	=> $row[4],
                	'extra  '	=> $row[5],
                );
            }
            return $this->_fields[$tbname];
        }else{
            return NULL;
        }
	}
	
	/**
	 * 过滤字段不存在的数据
	 * @param  string $tbname 表名
	 * @param  array $data   数据
	 * @return array         过滤后的数据
	 */
	public function filter($tbname, $data){
		$fields = $this->get_fields($tbname);
		foreach($data as $field => $val){
			if(!array_key_exists($field, $fields)){
				unset($data[$field]);
			}
		}
	}
	
	/**
	 * 插入数据
	 * @param  string $tbname 表名
	 * @param  array $data   数据
	 * @return integer         主键自增值
	 */
	public function insert($tbname, $data){
		$dataStr = $this->array2sql($tbname, $data, 'insert');
		$sql = "INSERT INTO `{$tbname}` $dataStr";
		$re = $this->query($sql);
		
		if(defined('DEBUG_PR') && DEBUG_PR == true){
			if(!isset($trace))$trace = stack_trace(false);
			$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re);
		}
		if(defined('DEBUG_FB') && DEBUG_FB == true){
			if(!isset($trace))$trace = stack_trace(false);
			fb(array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re), 'insert');
		}
		
		if($re){
			return $this->insert_id();
		} else {
			return - 1;
		}
	}
	
	/**
	 * 更新插入数据，表必须有主键或唯一索引
	 * @param  string $tbname 表名
	 * @param  array $data   数据
	 * @return integer         影响记录行数
	 */
	public function replace($tbname, $data){
		$dataStr = $this->array2sql($tbname, $data, 'insert');
		$sql = "REPLACE INTO `{$tbname}` $dataStr";
		$re = $this->query($sql);
		
		if(defined('DEBUG_PR') && DEBUG_PR == true){
			if(!isset($trace))$trace = stack_trace(false);
			$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re);
		}
		if(defined('DEBUG_FB') && DEBUG_FB == true){
			if(!isset($trace))$trace = stack_trace(false);
			fb(array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re), 'replace');
		}
		
		if($re){
			return $this->affected_rows();	// 1 插入，2 更新
		} else {
			return $re;
		}
	}
	
	/**
	 * 更新记录
	 * @param  string $tbname 表名
	 * @param  array $data   数据
	 * @return integer         影响记录行数
	 */
	public function update($tbname, $select, $data){
		if(empty($select))return -3;
		$selectStr = $this->array2sql($tbname, $select, 'select');
		$dataStr = $this->array2sql($tbname, $data, 'update');
		$sql = "UPDATE `{$tbname}` SET {$dataStr} WHERE {$selectStr} LIMIT 1";
		$re = (int)$this->query($sql, 'UNBUFFERED');
		
		if(defined('DEBUG_PR') && DEBUG_PR == true){
			if(!isset($trace))$trace = stack_trace(false);
			$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re);
		}
		if(defined('DEBUG_FB') && DEBUG_FB == true){
			if(!isset($trace))$trace = stack_trace(false);
			fb(array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re), 'update');
		}
		
		if($re){
			return $this->affected_rows();	// 1 更新，2 无变化
		} else {
			return $re;
		}
	}
	/**
	 * 累加
	 * @param  string  $tbname    表名
	 * @param array $select 查询条件
	 * @param  string  $field 字段名
	 * @param  integer $range 累加幅度
	 * @return boolean         成功与否
	 */
	public function incre($tbname, $select, $field, $range = 1){
		$selectStr = $this->array2sql($tbname, $select, 'select');
		$sql = "UPDATE `{$tbname}` SET `{$field}`=`{$field}`+{$range} WHERE {$selectStr} LIMIT 1";
		$re = $this->query($sql);

		if(defined('DEBUG_PR') && DEBUG_PR == true){
			if(!isset($trace))$trace = stack_trace(false);
			$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re);
		}
		if(defined('DEBUG_FB') && DEBUG_FB == true){
			if(!isset($trace))$trace = stack_trace(false);
			fb(array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re), 'adder');
		}
		
		return $re;
	}

	/**
	 * 累减
	 * @param  string  $tbname    表名
	 * @param array $select 查询条件
	 * @param  string  $field 字段名
	 * @param  integer $range 累减幅度
	 * @return boolean         成功与否
	 */
	public function degre($tbname, $select, $field, $range = 1){
		$selectStr = $this->array2sql($tbname, $select, 'select');
		$sql = "UPDATE `{$tbname}` SET `{$field}`=`{$field}`-{$range} WHERE {$selectStr} LIMIT 1";
		$re = $this->query($sql);

		if(defined('DEBUG_PR') && DEBUG_PR == true){
			if(!isset($trace))$trace = stack_trace(false);
			$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re);
		}
		if(defined('DEBUG_FB') && DEBUG_FB == true){
			if(!isset($trace))$trace = stack_trace(false);
			fb(array('trace' => $trace, 'sql' => $sql, 'data' => $data, 'result' => $re), 'degre');
		}
		
		return $re;
	}
	
	/**
	 * 删除记录
	 *
	 * @param string $tbname
	 * @param array $select
	 * @return integer
	 */
	/**
	 * 删除记录
	 * @param  string  $tbname 表名
	 * @param  array  $select 查询条件
	 * @param  boolean $limit  是否限定只处理一条记录
	 * @return integer          影响记录行数
	 */
	public function delete($tbname, $select, $limit = true){
		if(empty($select))return -3;
		$selectStr = $this->array2sql($tbname, $select, 'select');
		$sql = "DELETE FROM `{$tbname}` WHERE $selectStr";
		if($limit)$sql .= ' LIMIT 1';
		$re = (int)$this->query($sql);
		
		if(defined('DEBUG_PR') && DEBUG_PR == true){
			if(!isset($trace))$trace = stack_trace();
			$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $re);
		}
		if(defined('DEBUG_FB') && DEBUG_FB == true){
			if(!isset($trace))$trace = stack_trace();
			fb(array('trace' => $trace, 'sql' => $sql, 'data' => $re), 'delete');
		}
			
		if($re){
			return $this->affected_rows();	// 1 更新，2 无变化
		} else {
			return $re;
		}
	}
	
	/**
	 * 查询返回第一条满足条件的记录的指定字段
	 * @param  string $tbname 表名
	 * @param  array  $select 查询条件
	 * @param  string $field  返回字段
	 * @return mixed         字段数据
	 */
	public function get_col($tbname, $select = array(), $field = '*'){
		$selectStr = $this->array2sql($tbname, $select, 'select');
		if(!empty($selectStr)){
			$whereStr = " WHERE $selectStr";
		} else {
			$whereStr = '';
		}
		$sql = "SELECT $field FROM `{$tbname}` {$whereStr} LIMIT 1";
		return $this->sql_col($sql, $field);
	}
	
	/**
	 * 查询返回所有满足条件的记录的指定字段
	 * @param  stirng $tbname 表名
	 * @param  array  $select 查询条件
	 * @param  string $field  返回字段
	 * @return array         字段数据
	 */
	function get_cols($tbname, $select = array(), $field = '*'){
        $selectStr = $this->array2sql($tbname, $select, 'select');
		if(!empty($selectStr)){
			$whereStr = " WHERE $selectStr";
		} else {
			$whereStr = '';
		}
		$sql = "SELECT $field FROM `{$tbname}` {$whereStr}";
		return $this->sql_cols($sql, $field);
    }
    
	/**
	 * 查询返回第一条满足条件的记录的指定字段
	 * @param  string $sql   SQL
	 * @param  string $field 返回字段
	 * @return mixed        字段数据
	 */
	public function sql_col($sql, $field = ''){
		$res = $this->query($sql);
		if($res){
			if($field == ''){
				$field = $this->result($res, 0);
			}else{
				/* $fields = $this->get_fields($tbname);
				if(!array_key_exists($field, $fields)){
					return false;
				} */
				$row = $this->fetch_array($res);
				$field = $row[$field];
			}
			$this->free_result($res);
			// 插件处理
			if(defined('PLUGIN_OPEN') && PLUGIN_OPEN == true){
				$filter_info = has_filter();
				if($filter_info){	// 插件处理
					$field = do_filter($field, $filter_info);
				}
			}
			if(defined('DEBUG_PR') && DEBUG_PR == true){
				if(!isset($trace))$trace = stack_trace();
				$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $field);
			}
			if(defined('DEBUG_FB') && DEBUG_FB == true){
				if(!isset($trace))$trace = stack_trace();
				fb(array('trace' => $trace, 'sql' => $sql, 'data' => $field), 'sql_col');
			}
			
			return $field;
		} else {
			return NULL;
		}
	}
	
	/**
	 * 查询返回所有满足条件的记录的指定字段
	 * @param  stirng $sql SQL
	 * @param  string $field  返回字段
	 * @return array         字段数据
	 */
	function sql_cols($sql, $field = ''){
        $res = $this->query($sql);
        if ($res !== false){
	        // 插件处理
			if(defined('PLUGIN_OPEN') && PLUGIN_OPEN == true){
				$filter_info = has_filter();
			}else{
				$filter_info = null;
			}
            $arr = array();
            if($field == ''){
	            while ($row = $this->fetch_row($res)){
	            	if($filter_info){	// 插件处理
						$row[0] = do_filter($row[0], $filter_info);
					}
	                $arr[] = $row[0];
	            }
            }else{
            	/* $fields = $this->get_fields($tbname);
				if(!array_key_exists($field, $fields)){
					return false;
				} */
            	while ($row = $this->fetch_array($res)){
            		if($filter_info){	// 插件处理
						$row[$field] = do_filter($row[$field], $filter_info);
					}
	                $arr[] = $row[$field];
	            }
            }
            $this->free_result($res);
            if(defined('DEBUG_PR') && DEBUG_PR == true){
            	if(!isset($trace))$trace = stack_trace();
				$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $arr);
			}
			if(defined('DEBUG_FB') && DEBUG_FB == true){
				if(!isset($trace))$trace = stack_trace();
				fb(array('trace' => $trace, 'sql' => $sql, 'data' => $arr), 'sql_cols');
			}
			
            return $arr;
        }else{
            return NULL;
        }
    }
    
    /**
     * 统计满足条件的记录数
     * @param  stirng $tbname 表名
     * @param  array  $select 查询条件
     * @return integer         记录数
     */
	public function get_counts($tbname, $select = array()){
		$selectStr = $this->array2sql($tbname, $select, 'select');
		if(!empty($selectStr)){
			$whereStr = " WHERE $selectStr";
		} else {
			$whereStr = '';
		}
		$sql = "SELECT COUNT(*) AS `total` FROM `{$tbname}` {$whereStr}";
		
		return $this->sql_col($sql, $field = 'total');
	}
	
	/**
	 * 求和
	 * @param  string $tbname 表名
	 * @param  string $field  求和字段
	 * @param  array  $select 查询条件
	 * @return integer         和
	 */
	public function get_sum($tbname, $field, $select = array()){
		$selectStr = $this->array2sql($tbname, $select, 'select');
		if(!empty($selectStr)){
			$whereStr = " WHERE $selectStr";
		} else {
			$whereStr = '';
		}
		$sql = "SELECT sum($field) AS `total` FROM `{$tbname}` {$whereStr}";
		
		return $this->sql_col($sql, $field = 'total');
	}
	
	/**
	 * 读取第1条满足条件的记录
	 * @param  string $tbname 表名
	 * @param  array  $select 查询条件
	 * @param  string $fields 返回字段
	 * @return array         记录关联数组
	 */
	public function get_row($tbname, $select = array(), $fields = '*'){
		$selectStr = $this->array2sql($tbname, $select, 'select');
		if(!empty($selectStr)){
			$whereStr = " WHERE $selectStr";
		} else {
			$whereStr = '';
		}
		$sql = "SELECT $fields FROM `{$tbname}` {$whereStr} LIMIT 1";
		return $this->sql_row($sql);
	}
	
	/**
	 * 读取第1条满足条件的记录
	 * @param  string $sql SQL
	 * @return array         记录关联数组
	 */
	public function sql_row($sql = ''){
		$res = $this->query($sql);
		if($res){
			$re = $this->fetch_array($res);
			$this->free_result($res);			
			if(defined('DEBUG_PR') && DEBUG_PR == true){
				if(!isset($trace))$trace = stack_trace();
				$GLOBALS['debug_info'][] = array('trace' => $trace, 'sql' => $sql, 'data' => $re);
			}
			if(defined('DEBUG_FB') && DEBUG_FB == true){
				if(!isset($trace))$trace = stack_trace();
				fb(array('trace' => $trace, 'sql' => $sql, 'data' => $re), 'sql_row');
			}
			
			return $re;
		} else {
			return null;
		}
	}

	/**
	 * 读取满足条件的全部记录
	 * @param  string $tbname 表名
	 * @param  string $fields 返回字段
	 * @param  array  $select 查询条件
	 * @param  array  $order  排序条件
	 * @return array         记录列表
	 */
	public function get_all($tbname, $fields = '*', $select = array(), $order = array()){
		$whereStr = '';
		$orderStr = '';
		if(!empty($select)){
			$selectStr = $this->array2sql($tbname, $select, 'select');
			if(!empty($selectStr)){
				$whereStr = " WHERE $selectStr";
			}
		}
		if(!empty($order)){
			$orderStr = $this->array2sql($tbname, $order, 'order');
		}
		$sql = "SELECT $fields FROM `{$tbname}` {$whereStr} {$orderStr} LIMIT 1000000";	// 话说全部，也限制最多1百万
		return $this->sql_all($sql);
	}
	
	/**
	 * 读取满足条件的记录
	 * @param  string  $tbname 表名
	 * @param  string  $fields 返回字段
	 * @param  array   $select 查询条件
	 * @param  array   $order  排序条件
	 * @param  integer $page   页码
	 * @param  integer $size   单次返回记录数
	 * @param  integer  $offset 页码范围
	 * @return array          记录列表
	 */
	public function get_list($tbname, $fields = '*', $select = array(), $order = array(), $page = 1, $size = 10, $offset = PAGE_OFFSET){
		$whereStr = '';
		$orderStr = '';
		if(!empty($select)){
			$selectStr = $this->array2sql($tbname, $select, 'select');
			if(!empty($selectStr)){
				$whereStr = " WHERE $selectStr";
			}
		}
		if(!empty($order)){
			$orderStr = $this->array2sql($tbname, $order, 'order');
		}
		$sql = "SELECT $fields FROM `{$tbname}` {$whereStr} {$orderStr}";
		return $this->sql_list($sql, $page, $size, $offset);
	}
	
	/**
	 * 读取满足条件的记录
	 * @param  string  $sql SQL
	 * @param  integer $page   页码
	 * @param  integer $size   单次返回记录数
	 * @param  integer  $offset 页码范围
	 * @return array          记录列表
	 */
	public function sql_list($sql, $page = 1, $size = 10, $offset = PAGE_OFFSET){
		$size = min(10000, max(2, intval($size)));	// 列表单次限制最多1万条
		$pos = $size *($page - 1);
		// $sql = preg_replace('/,\s+/i', ',', $sql);
		$_sql = preg_replace('/^SELECT\s+/i', 'SELECT SQL_CALC_FOUND_ROWS ', $sql, 1);
		$_sql .= " LIMIT {$pos},{$size}";
		$res = $this->query($_sql);
		if($res){
			$re['total']= $this->sql_col('SELECT FOUND_ROWS() AS `total`', 'total');
			$re['size']	= $size;
			$re['page']	= $page;
			$re['sql']	= $sql;
			$re['list']	= array();
			// 插件处理
			if(defined('PLUGIN_OPEN') && PLUGIN_OPEN == true){
				$filter_info = has_filter();
			}else{
				$filter_info = null;
			}
			$i = 0;
			while(( $row = $this->fetch_array($res)) && $i < $size){
				if($filter_info){	// 插件处理
					$row = do_filter($row, $filter_info);
				}
				$re['list'][$i]= $row;
				$i ++;
			}
			$this->free_result($res);
			if(defined('DEBUG_PR') && DEBUG_PR == true){
				if(!isset($trace))$trace = stack_trace();
				$GLOBALS['debug_info'][] = array('trace' => $trace, 'data' => $re);
			}
			if(defined('DEBUG_FB') && DEBUG_FB == true){
				if(!isset($trace))$trace = stack_trace();
				fb(array('trace' => $trace, 'data' => $re), 'sql_list');
			}
			
			if($offset > 0){	// 计算页码参数
				$re['pagelist'] = $this->pagelist($re['total'], $size, $page, $offset);
			}
			
			return $re;
		} else {
			return null;
		}
	}
	
	/**
	 * 读取满足条件的全部记录
	 * @param  string $sql SQL
	 * @return array         记录列表
	 */
	public function sql_all($sql){
		// $sql = preg_replace('/,\s+/i', ',', $sql);
		$_sql = preg_replace('/^SELECT\s+/i', 'SELECT SQL_CALC_FOUND_ROWS ', $sql, 1);
		$res = $this->query($_sql);
		if($res){
			$re['total']= $this->sql_col('SELECT FOUND_ROWS() AS `total`', 'total');
			$re['sql']= $sql;
			$re['list']= array();
			// 插件处理
			if(defined('PLUGIN_OPEN') && PLUGIN_OPEN == true){
				$filter_info = has_filter();
			}else{
				$filter_info = null;
			}
			$i = 0;
			while($row = $this->fetch_array($res)){
				if($filter_info){	// 插件处理
					$row = do_filter($row, $filter_info);
				}
				$re['list'][$i]= $row;
				$i ++;
			}
			$this->free_result($res);
			if(defined('DEBUG_PR') && DEBUG_PR == true){
				if(!isset($trace))$trace = stack_trace();
				$GLOBALS['debug_info'][] = array('trace' => $trace, 'data' => $re);
			}
			if(defined('DEBUG_FB') && DEBUG_FB == true){
				if(!isset($trace))$trace = stack_trace();
				fb(array('trace' => $trace, 'data' => $re), 'sql_all');
			}
		
			return $re;
		} else {
			return null;
		}
	}
	
	/**
	 * 计算并生成页码列表
	 * @param  integer  $total  记录总数
	 * @param  integer  $size   单页记录数
	 * @param  integer  $page   当前页码
	 * @param  integer $offset 页码范围，相对当前页偏移值
	 * @return array          页码列表
	 */
	public function pagelist($total, $size, $page, $offset = 5){
		$pages = array();
		$pages['guid']		= str_replace('.', '_', microtime(true));
		$pages['page']		= intval($page);
		$pages['size']		= max(intval($size), 1);
		$pages['total']		= $total;
		$pages['pagecount'] = $pagecount = ceil($total / $size);
		$pages['first']		= 0;
		$pages['prev']		= 0;
		$pages['next']		= 0;
		$pages['last']		= 0;
		
		if($page > 1)$pages['prev'] = $page - 1;
		if($page < $pagecount)$pages['next'] = $page + 1;
	
		$dset = $offset * 2;
		$begin = $page - $offset;
		if($begin < 1)$begin = 1;
		
		$end = $begin + $dset;
		if($end > $pagecount)$end = $pagecount;
		if($end - $begin < $dset){
			$begin = $end - $dset;
			if($begin < 1)$begin = 1;
		}
		
		if($page - 1 > $offset)$pages['first'] = 1;
		if($pagecount - $page > $offset)$pages['last'] = $pagecount;
		for($i = $begin; $i <= $end; $i ++){
			$pages['pagelist'][] = $i;
		}
		
		return $pages;
	}
}
?>
